import React, { Fragment } from 'react';
import { Table, Tooltip } from 'antd';
import { FormattedMessage } from 'umi-plugin-react/locale';
import _ from 'lodash';
import getCachingKeys from 'umi/getCachingKeys';
import { isEmptyParam, types } from '@/utils/utils';
import { StateType } from '@/common-typings';
import ResizeObserver from '@/utils/resizeObserver';
import { formatText, getStrLen, getColumnSearchProps } from './utils';

export interface TableConfigProps {
  header: any[];
  data: any[];
  config?: any;
  loading?: boolean;
  [propName: string]: any;
}

interface CreateTableProps {
  tableConfig: TableConfigProps;
  [propName: string]: any;
}

class CreateTable extends React.PureComponent<CreateTableProps, StateType> {
  public state = {
    height: 450,
  };

  /**
   * 默认分页配置
   */
  public defaultPagination = {
    showSizeChanger: true,
    showQuickJumper: true,
    pageSizeOptions: ['10', '20', '50', '200', '500'],
  };

  /**
   * 默认table配置
   */
  public defaultConfig = {
    className: '',
    bordered: true,
    showHeader: true,
  };

  /**
   * 添加事件监听
   */
  componentDidMount(): void {
    if (!this.props.tableConfig.height) {
      const { pathname = '' } = window.location;

      // 300ms后执行一次方法
      _.debounce(this.updateHeight, 300)();

      // 添加事件监听
      ResizeObserver.add(pathname, this.updateHeight)
        .requireMatchRouter(pathname)
        .start(pathname);
    }
  }

  /**
   * 卸载事件监听
   */
  componentWillUnmount() {
    const pathList = getCachingKeys();
    ResizeObserver.getQueue().forEach((item: StateType) => {
      if (!pathList.some(i => i === item.id)) {
        ResizeObserver.remove(item.id);
      }
    });
  }

  /**
   * 数据源key与id绑定，值不可重复
   */
  bindDataSourceKey = () => {
    const { tableConfig } = this.props;
    const { data, bindKey = 'id' } = tableConfig;
    const result = data.map((item: any, index) => {
      item.key = item[bindKey] || index;
      return item;
    });
    return result;
  };

  /**
   * 获取数据的前端汇总值，根据summary来判别是否需要累加
   * 不考虑数据的重复遍历情况， 因为后台header的数据条数很少
   */
  getTableDataSummary = () => {
    const { tableConfig } = this.props;
    const { header, data } = tableConfig;
    const summary = header.some(item => item.summary);
    const total: any[] = []; // 汇总数据

    // 是否需要汇总并且data有值
    if (summary && data.length) {
      header.forEach(headerItem => {
        // 排除隐藏行
        if (!headerItem.hidden) {
          const obj = {};
          // 判断子项数据是否需要汇总
          if (headerItem.summary) {
            // 目前只考虑数字类型的总计
            obj[headerItem.dataIndex] = data.reduce(
              (accumulator, currentValue) => accumulator + +currentValue[headerItem.dataIndex],
              0,
            );

            // 默认的文本
          } else if (headerItem.defaultText) {
            obj[headerItem.dataIndex] = headerItem.defaultText;

            // 增加一个过滤的的文本，过滤文本不在汇总内显示
          } else {
            obj[headerItem.dataIndex] = '|';
          }
          const totalObj = {
            content: obj[headerItem.dataIndex],
            key: headerItem.dataIndex,
          };
          // 有总计并且有render
          if (headerItem.render && headerItem.summary) {
            total.push(Object.assign({}, totalObj, { render: headerItem.render }));
          } else {
            total.push(totalObj);
          }
        }
      });
    }
    return total;
  };

  /**
   * 计算出数据源中对应条数据最大长度
   */
  getDataSourceItemMaxLength = () => {
    const { tableConfig } = this.props;
    const { header, data } = tableConfig;
    const maxLengthObj = { hasOperates: false }; // 最小宽度的对象
    // 对dataSource数据进行处理
    if (data.length) {
      header.map(headerItem => {
        // 获取没项数据的最大长度
        if (headerItem.dataIndex !== 'operates') {
          const arr: any[] = [];
          data.map(dataItem => {
            if (dataItem.hasOwnProperty(headerItem.dataIndex)) {
              if (
                types(dataItem[headerItem.dataIndex]) !== 'array' &&
                types(dataItem[headerItem.dataIndex]) !== 'object'
              ) {
                arr.push(getStrLen(`${dataItem[headerItem.dataIndex]}`));
              }
            }
            return dataItem;
          });
          maxLengthObj[headerItem.dataIndex] = arr ? Math.floor(Math.max.apply(null, arr)) : 0;
        } else {
          maxLengthObj.hasOperates = true;
        }
        return headerItem;
      });
    }
    return maxLengthObj;
  };

  /**
   * 原数据处理器
   * @param data
   */
  dataSourceHandle = (data: any[]) => ({
    list: this.bindDataSourceKey(),
    total: this.getTableDataSummary(),
    maxLenObj: this.getDataSourceItemMaxLength(),
  });

  /**
   * tableItem根据字段长度来控制显示宽度，最大宽度360
   * @param len
   */
  getWidth = (len: number) => {
    if (len >= 15) {
      return len * 15 > 360 ? 360 : len * 13;
    }
    if (len > 5) {
      return len * 15;
    }
    return 70;
  };

  /**
   * header计算宽度，计算出每条列数据宽度以及总宽度
   * 目
   * @param data
   * @param maxLenObj
   */
  columnsCalcWidth = (data: any[], maxLenObj: any) => {
    data = [...data].filter(item => !item.hidden);
    const len = 30; // 设置最大显示的字符长度
    let totalWidth = 0; // table的最小宽度
    let width = 0; // tableItem的宽度

    const { expandedData = [], emptyColumn } = this.props.tableConfig;
    if (emptyColumn && !expandedData.length) {
      data.unshift({
        width: 50,
      });
    }

    data.map((item, index) => {
      item.key = item.dataIndex || Date.now();
      // 判断maxLenObj是否含有id
      if (maxLenObj.hasOwnProperty(item.dataIndex)) {
        // 对比title以及数据，求的最大值
        width = this.getWidth(Math.max(maxLenObj[item.dataIndex], getStrLen(item.title)));
        if (item.width) {
          if (types(item.width) === 'number') {
            ({ width } = item);
          }
        } else {
          item.width = width;
        }
        totalWidth += width;

        // 如果配置中传递有宽度并且是数据类型，累加宽度
      } else if (item.width && types(item.width) === 'number') {
        totalWidth += item.width;

        // 如果是操作项
      } else if (maxLenObj.hasOperates) {
        if (item.width && types(item.width) === 'number') {
          ({ width } = item);
          totalWidth += width;
        } else {
          item.width = 120; // 操作区域宽度
          totalWidth += item.width;
        }

        // 如果没有数据，把title的作为宽度
      } else {
        item.width = this.getWidth(getStrLen(item.title));
        totalWidth += item.width;
      }

      // 当tableItem中无render方法，根据长度情况判断是否显示提示信息
      if (!item.render) {
        item.render = (text: any, row: any) => {
          if (isEmptyParam(text)) {
            return '--';
          }
          if (text === '|') {
            return '';
          }
          if (text.toString().length <= len) {
            return formatText(text, item);
          }
          return (
            <Tooltip placement="top" title={text}>
              <span>{`${text.toString().slice(0, len)}...`}</span>
            </Tooltip>
          );
        };
      }

      // 居中对齐
      item.align = 'center';

      // 判断是否有相应配置
      if (item.filterBindDataIndex) {
        const searchProps = getColumnSearchProps(item.filterBindDataIndex, this, item.placeholder);
        Object.keys(searchProps).forEach(key => {
          item[key] = searchProps[key];
        });
      }
      return item;
    });

    return {
      data,
      totalWidth,
    };
  };

  /**
   * 分页配置
   */
  getPaginationConfig = () => {
    const { tableConfig } = this.props;
    const { pagination } = tableConfig;
    let newPagination;
    if (pagination) {
      newPagination = {
        ...this.defaultPagination,
        pageSize: pagination.size,
        current: pagination.page,
        total: pagination.total,
        showTotal: () => (
          <Fragment>
            <FormattedMessage id="globalComponent.table.total" />
            {pagination.total}
            <FormattedMessage id="globalComponent.table.records" />
            <FormattedMessage id="globalComponent.table.sort" />
            {`${pagination.page}/${Math.ceil(pagination.total / pagination.size)}`}
          </Fragment>
        ),
      };
    }
    return newPagination || false;
  };

  /**
   * 渲染footer的总计
   * @param dataSource
   */
  tableFooter = (dataSource: StateType) => {
    if (dataSource.total && dataSource.total.length) {
      const { rowSelection } = this.props.tableConfig;
      return (
        <tr className="ant-table-row" style={{ background: '#f5f5f5' }}>
          {rowSelection && <td></td>}
          {dataSource.total.map((item: any) => (
            <td key={item.key}>
              {item.render && (item.render ? item.render(item.content) : item.content)}
              {!item.render && (item.content !== '|' ? item.content : '')}
            </td>
          ))}
        </tr>
      );
    }
    return null;
  };

  /**
   * 折叠考虑
   */
  expandedRowRender = () => {
    const { expandedColumns = [], expandedData = [] } = this.props.tableConfig;
    return (
      <Table
        showHeader={false}
        bordered={false}
        columns={expandedColumns}
        dataSource={expandedData}
        pagination={false}
      />
    );
  };

  /**
   * 窗口变化时更新高度
   */
  updateHeight = () => {
    const pageCardMargin = 120;
    const pageCardPadding = 50;
    const pagePaginationMargin = 46;
    const pageBody = document.querySelector('#root') as HTMLElement;
    const pageForm = document.querySelector(
      '.fade-transform-enter > .fade-transform-enter .st-form',
    ) as HTMLElement;
    const pageCardTitle = document.querySelector(
      '.fade-transform-enter > .fade-transform-enter .st-card-title',
    ) as HTMLElement;
    const pageTableTitle = document.querySelector(
      '.fade-transform-enter > .fade-transform-enter .st-content-title',
    ) as HTMLElement;
    const pagePagination = document.querySelector(
      '.fade-transform-enter > .fade-transform-enter .st-content .ant-table-pagination',
    ) as HTMLElement;

    const pageBodyHeight = pageBody ? pageBody.clientHeight : 0;
    const pageFormHeight = pageForm ? pageForm.offsetHeight : 0;
    const pageCardTitleHeight = pageCardTitle ? pageCardTitle.offsetHeight : 0;
    const pageTableTitleHeight = pageTableTitle ? pageTableTitle.offsetHeight : 0;
    const pagePaginationHeight = pagePagination ? pagePagination.offsetHeight : 0;

    const totalHeight =
      pageCardMargin +
      pageCardPadding +
      pagePaginationMargin +
      pageFormHeight +
      pageCardTitleHeight +
      pageTableTitleHeight +
      pagePaginationHeight;

    /**
     * 此处60有问题。。。
     */
    this.setState(preState => ({
      ...preState,
      height: pageBodyHeight - totalHeight - 60,
    }));
  };

  render() {
    const { tableConfig } = this.props;
    const {
      header,
      data,
      loading,
      rowSelection,
      config = {},
      height,
      hiddenScroll = false,
      changePaginationCallBack, // table改变回掉
      onTableChange, // 自定义table改变的回掉
      tableFiltersTool, // 自定义的处理器
    } = tableConfig;
    const dataSource = this.dataSourceHandle(data);
    const columns = this.columnsCalcWidth(header, dataSource.maxLenObj);
    const pagination = this.getPaginationConfig();
    const newHeight = height || this.state.height;

    // 考虑table的汇总数据
    const BodyWrapper = (props: any) => (
      <tbody {...props}>
        <React.Fragment>
          {props.children}
          {this.tableFooter(dataSource)}
        </React.Fragment>
      </tbody>
    );

    const scroll = !hiddenScroll
      ? { x: columns.totalWidth, y: newHeight }
      : { x: columns.totalWidth };
    return (
      <div className="st-content">
        <div className="st-content__body" style={{ width: '100%' }}>
          <div className="st-content-title">
            {// 考虑头部DOM的节点
            tableConfig.tableTitle && tableConfig.tableTitle()}
          </div>
          <Table
            components={{ body: { wrapper: BodyWrapper } }}
            loading={loading}
            dataSource={dataSource.list}
            columns={columns.data}
            rowSelection={rowSelection || null}
            scroll={scroll}
            pagination={pagination}
            {...this.defaultConfig}
            {...config}
            onChange={(paginates, filters, sorter) => {
              // 判断是否有onTableChange事件
              if (onTableChange) {
                onTableChange(paginates, filters, sorter);

                // 如果没有则进入下面判断
              } else {
                let callbackParams = {};

                // 分页参数
                if (paginates && !_.isEmpty(paginates)) {
                  callbackParams = {
                    pageNum: paginates.current,
                    pageSize: paginates.pageSize,
                    total: paginates.total,
                  };
                }

                // filters参数
                if (filters && types(filters) === 'object' && !_.isEmpty(filters)) {
                  callbackParams = {
                    ...callbackParams,
                    // 新增一个filters字段存储变动的值
                    filters: tableFiltersTool ? tableFiltersTool(filters) : filters,
                  };
                }

                // 排序参数
                if (sorter && !_.isEmpty(sorter)) {
                  // callbackParams = { ...callbackParams, ...filters };
                }

                // 分页回掉方法
                if (changePaginationCallBack) {
                  changePaginationCallBack(callbackParams);
                }
              }
            }}
          />
        </div>
      </div>
    );
  }
}

export default CreateTable;
